package util;

import beans.ChessPiece;
import beans.Color;
import beans.Move;
import beans.Piece;
import beans.Position;
import board.Board;

/**
 * This class can be used to parse moves from either long or short algebraic notations.
 * @author Josep M Sobrepere
 */
public class MoveParser {
	/**
	 * This function can be used to parse a move from short algebraic notation (ie: Nf3) 
	 * 
	 * @param move the move to be parsed 
	 * @param turn whose side made the move
	 * @param board a board with the position before the move was made (this function will not register the move in the board).
	 * @return a javabean representing the move.
	 */
	public static Move fromShortNotation(String move, Color turn, Board board, int numberMove){
		ChessPiece promotionPiece =null;
		move = move.trim();
		String originalMove = move;
		
		boolean check = move.contains("+");
		boolean mate = move.contains("#");		
		
		move=move.replace("+", "");
		move=move.replace("#", "");
		
		if (move.startsWith("O-O")){
			int row = (turn == Color.WHITE)?0:7;
			int file =(move.equals("O-O"))?6:2;
			return new Move(new Position(4,row), new Position(file,row), new Piece(turn, ChessPiece.KING),null, null, originalMove, check, mate,false,false,numberMove);
		}
		
		Position from=null;
		Position to=null;
		
		if(move.contains("=")){
			int ePos= move.indexOf("=");
			promotionPiece = Util.getChessPieceFromInitial(move.charAt(ePos+1));
			to=Util.getPositionFromStr(move.substring(ePos-2,ePos));
			move = move.substring(0, ePos);
		}else{
			to=Util.getPositionFromStr(move.substring(move.length()-2));
		}
		
		Piece capturedPiece = board.getPiece(to);
				
		int colorPawnIncrement = (turn == Color.WHITE)?-1:1;
		
		if(move.length()==2){						
			int y = to.getY()+colorPawnIncrement;
			do{
				Piece square = board.getPiece(to.getX(), y); 
				if(square!=null && square.getKind()== ChessPiece.PAWN && square.getColor()==turn){
					from = new Position(to.getX(),y);									
					return new Move(from, to, new Piece(turn, ChessPiece.PAWN), capturedPiece, promotionPiece,originalMove,check, mate,board.checkMoveEnPassant(from, to),false,numberMove);					
				}else{
					y = y+colorPawnIncrement;
				}				
			}while(from==null);			
		}		
		
		move=move.substring(0, move.length()-2);
		char pieceInitial = move.charAt(0);			
		if(pieceInitial>96){
			//si és un peo, vol dir que és una captura, per tant
			from= new Position(pieceInitial-97, to.getY()+colorPawnIncrement);
			boolean takeEnPassant=false;
			if(capturedPiece==null){
				int i = (turn==Color.WHITE)?-1:1;
				capturedPiece= board.getPiece(to.getX(), to.getY()+i);
				takeEnPassant=true;				
			}
			return new Move(from, to, new Piece(turn, ChessPiece.PAWN), capturedPiece,promotionPiece, originalMove,check, mate,false,takeEnPassant,numberMove);
		}else{
			ChessPiece cp = null;
			String help = null;
			cp = Util.getChessPieceFromInitial(pieceInitial);			
			move = move.replaceAll("x", "");
			move = move.replaceAll("X", "");
			if(move.length()>1){
				help = move.substring(1);
			}
			return new Move(board.searchPositionPiece(cp, to, turn, help), to, new Piece(turn, cp), capturedPiece,null,originalMove,check,mate,false,false,numberMove);	
		}
	}
	
	/**
	 * This function can be used to parse a move from long algebraic notation (ie: g1f3)
	 * 
	 * @param moveStr the move to be parsed 
	 * @param turn whose side made the move
	 * @param board a board with the position before the move was made (this function will also register the move in the board).
	 * @return a javabean representing the move.
	 */
	public static Move fromLongNotation(String moveStr, Board board, int numberMove){
		Position from = Util.getPositionFromStr(moveStr.substring(0, 2));
		Position to = Util.getPositionFromStr(moveStr.substring(2,4));
		
		Piece piece = board.getPiece(from);				
		Piece capturedPiece = board.getPiece(to);
		ChessPiece piecePromotion=null;
		Color turn = piece.getColor();
		
		StringBuilder sb = new StringBuilder();
		boolean takeEnPassant=false;
		
		switch (piece.getKind()){
		case BISHOP:
			sb.append('B');
			break;
		case KING:
			sb.append('K');			
			break;
		case KNIGHT:
			sb.append('N');			
			break;
		case QUEEN:
			sb.append('Q');
			break;			
		case ROOK:
			sb.append('R');
			break;							
		}
		
		if(piece.getKind()!=  ChessPiece.PAWN && piece.getKind() != ChessPiece.KING){
			Position candidates[] = board.getPiecesWithAccesToPosition(to, piece.getKind(), turn,-1,true);			
			if(candidates.length==2){
				if(candidates[0].getX()!=candidates[1].getX()){
					sb.append((char) (from.getX()+97));
				}else{
					sb.append((char) (from.getY()+49));
				}				
			}else if(candidates.length>2){
				sb.append(Util.getStrFromPosition(from));
			}
		}
		
		if(capturedPiece!=null){
			if (piece.getKind()==  ChessPiece.PAWN)
				sb.append((char) (from.getX()+97));	
			sb.append('x');
		}else if(piece.getKind()==ChessPiece.PAWN && from.getX()!=to.getX()){
			takeEnPassant=true;
			int i = (turn==Color.WHITE)?-1:1;
			capturedPiece= board.getPiece(to.getX(), to.getY()+i);
			sb.append((char) (from.getX()+97)).append("x");
		}		
		
		sb.append(Util.getStrFromPosition(to));		
		
		if(moveStr.length()==5){
			sb.append('=').append(String.valueOf(moveStr.charAt(4)).toUpperCase());
			piecePromotion= Util.getChessPieceFromInitial(String.valueOf(moveStr.charAt(4)).toUpperCase().charAt(0));
		}
		
		Move move = new Move(from, to, piece, capturedPiece,piecePromotion, sb.toString(), false, false, board.checkMoveEnPassant(from, to), takeEnPassant,numberMove);
		
		board.registerMove(move);
		sb = new StringBuilder(move.getShortAlgebraicNotation());
		
				
		int check =board.isCheck(turn,(move.isPawnEnPassant())?move.getFrom().getX():-1);
		switch (check){
		case 1:
			move.setCheck(true);
			sb.append('+');
			break;
		case 2:
			move.setCheck(true);
			move.setMate(true);
			sb.append('#');
			break;		
		}
		move.setShortAlgebraicNotation(sb.toString());		
		
		return move;
	}

}
